package cn.mini.mybatis.mybatis.builder;

import cn.mini.mybatis.mybatis.io.Resources;
import cn.mini.mybatis.mybatis.mapping.MappedStatement;
import cn.mini.mybatis.mybatis.mapping.SqlCommandType;
import cn.mini.mybatis.mybatis.session.Configuration;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class XMLConfigBuilder extends BaseBuilder{
    /**
     * 配置文件中的根节点即 configuration
     */
    private Element root;

    public XMLConfigBuilder(Reader reader) {
        // 1. 调用父类初始化Configuration
        super(new Configuration());
        // 2. dom4j 处理 xml
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new InputSource(reader));
            root = document.getRootElement();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    public Configuration parse() {
        parseConfiguration();
        return configuration;
    }


    /**
     * 解析 configurations下任意节点
     * 由于采用dom4j解析且维护配置文件根节点  configuration 节点下有很多子节点，所以这里使用递归的方式解析mappers内容
     */
    private void parseConfiguration() {
        // 如果解析其他节点可在此直接添加对应方法进行解析
        mapperElement(root.element("mappers"));
    }

    /**
     * 解析 mappers 节点
     * @param mappers mappers 元素
     */
    private void mapperElement(Element mappers) {
        if (mappers != null) {
            List<Element> mapperElements = mappers.elements("mapper");
            for (Element mapperElement : mapperElements) {
                String resource = mapperElement.attributeValue("resource");
                if (resource != null && !resource.trim().isEmpty()) {
                    try (Reader reader = Resources.getResourceAsReader(resource)) {
                        SAXReader saxReader = new SAXReader();
                        Document mapperDoc = saxReader.read(new InputSource(reader));
                        Element mapperRoot = mapperDoc.getRootElement();
                        String namespace = mapperRoot.attributeValue("namespace");

                        if (namespace == null || namespace.trim().isEmpty()) {
                            throw new IllegalArgumentException("Namespace cannot be empty in " + resource);
                        }

                        for (Element sqlElement : mapperRoot.elements()) {
                            String id = sqlElement.attributeValue("id");
                            if (id == null || id.trim().isEmpty()) {
                                throw new IllegalArgumentException("SQL id cannot be empty in " + resource);
                            }
                            String sqlCommandName = sqlElement.getName().toLowerCase();
                            SqlCommandType sqlCommandType;
                            switch (sqlCommandName) {
                                case "select":
                                    sqlCommandType = SqlCommandType.SELECT;
                                    break;
                                case "insert":
                                    sqlCommandType = SqlCommandType.INSERT;
                                    break;
                                case "update":
                                    sqlCommandType = SqlCommandType.UPDATE;
                                    break;
                                case "delete":
                                    sqlCommandType = SqlCommandType.DELETE;
                                    break;
                                default:
                                    throw new IllegalArgumentException("Unknown SQL command type: " + sqlCommandName);
                            }

                            String sql = sqlElement.getTextTrim();
                            String statementId = namespace + "." + id;
                            // 注册Mapper映射器
                            configuration.addMapper(Resources.classForName(namespace));
                            MappedStatement.Builder statementBuilder = new MappedStatement.Builder(statementId, sqlCommandType, sql);

//                            String parameterType = sqlElement.attributeValue("parameterType");
//                            if (parameterType != null && !parameterType.trim().isEmpty()) {
//                                statementBuilder.parameterType(Resources.classForName(parameterType));
//                            }
//
//                            String resultType = sqlElement.attributeValue("resultType");
//                            if (resultType != null && !resultType.trim().isEmpty()) {
//                                statementBuilder.resultType(Resources.classForName(resultType));
//                            }

                            configuration.addMappedStatement(statementBuilder.build());
                        }
                    } catch (DocumentException | IOException  | ClassNotFoundException e) {
                        throw new RuntimeException("Error parsing mapper XML: " + resource, e);
                    }
                }
            }
        }
    }

}
